package simulation;

import java.awt.Dimension;
import java.util.List;
import util.Location;
import util.Pixmap;
import util.Sprite;
import util.Vector;

/**
 * XXX.
 *
 * @author Robert C. Duvall
 */
public class Mass extends Sprite {
    // reasonable default values
    /**
     * The size of the mass.
     */
    public static final Dimension DEFAULT_SIZE = new Dimension(16, 16);
    /**
     * Image used in painting the mass.
     */
    public static final Pixmap DEFUALT_IMAGE = new Pixmap("mass.gif");
    /** */
    public static final double ENERGY_LOSS = 0.8;
    private Vector myAcceleration;
    private double myMass;
    /**
     * 
     * XXX.
     * @param x coordinate of mass
     * @param y coordinate of mass
     * @param mass of object
     * @param model view of simulations
     */
    public Mass(final double x, final double y,
                 final double mass, final Model model) {
        super(DEFUALT_IMAGE, new Location(x, y), DEFAULT_SIZE);
        myAcceleration = new Vector();
        myMass = mass;
    }

    @Override
    public final double getMass() {
        return myMass;
    }

    @Override
    public final void setMass(final double mass) {
        myMass = mass;
    }

    /**
     * Updates mass based on calculations from forces.
     * @param elapsedTime is time elapsed between each step
     * @param bounds are the bounds from the screen size to
     * @param forces are the forces that act on the mass
     * make sure objects do not fly off screen
     */
    @Override
    public final void update(final double elapsedTime, final Dimension bounds, List<Force> forces) {
        for (Force f : forces) {
            f.applyForce(this);
        }

        getVelocity().sum(myAcceleration);
        bounce(bounds);
        // convert force back into Mover's velocity
        myAcceleration.reset();
        // move mass by velocity
        super.update(elapsedTime, bounds, forces);
    }

    /**
     * Use the given force to change this mass's acceleration.
     * @param force that acts on acceleration
     */
    public void applyForce(final Vector force) {
        myAcceleration.sum(force);
    }

    /**
     * Convenience method - finds distance from one mass to another mass.
     * @param other is one mass where the distance is found from.
     * @return Location
     */
    public final double distance(final Mass other) {
        // this is a little awkward, so hide it
        return new Location(getX(), getY()).distance(new Location(other.getX(), other.getY()));
    }


    private void bounce(final Dimension bounds) {
        if (getRight() < 0) {
            setVelocity(new Vector(new double[] {Math.abs(getVelocity().getXChange()) * ENERGY_LOSS,
                        getVelocity().getYChange()}));
        } 
        else if (getLeft() > bounds.width) {
            setVelocity(new Vector(new double[] {-1 * Math.abs(getVelocity().getXChange()) * 
                                                 ENERGY_LOSS, getVelocity().getYChange()}));
        } 
        else if (getBottom() < 0) {
            setVelocity(new Vector(new double[] {getVelocity().getXChange(),
                        Math.abs(getVelocity().getYChange()) * ENERGY_LOSS}));
        } 
        else if (getTop() > bounds.height) {
            setVelocity(new Vector(new double[] 
            {getVelocity().getXChange(), -1 * Math.abs(getVelocity().getYChange()) * ENERGY_LOSS }));
        }
    }
}
